package middleware

import (
	"encoding/json"
	"errors"
	"net/http"
	"strings"

	"github.com/golang-jwt/jwt/v4"
	"github.com/iriver/ai-offer/backend/internal/config"
	"github.com/iriver/ai-offer/backend/internal/types"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/rest/httpx"
)

type Claims struct {
	UserId int64  `json:"userId"`
	Email  string `json:"email"`
	Role   string `json:"role"`
	jwt.RegisteredClaims
}

type JWTAuthMiddleware struct {
	Config config.Config
}

func NewJWTAuthMiddleware(c config.Config) *JWTAuthMiddleware {
	return &JWTAuthMiddleware{
		Config: c,
	}
}

func (m *JWTAuthMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// 从请求头获取令牌
		authHeader := r.Header.Get("Authorization")
		if authHeader == "" {
			httpx.WriteJson(w, http.StatusUnauthorized, types.NewErrorResponse(types.ErrUnauthorized, "未提供认证令牌"))
			return
		}

		// 解析令牌
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			httpx.WriteJson(w, http.StatusUnauthorized, types.NewErrorResponse(types.ErrUnauthorized, "认证令牌格式错误"))
			return
		}

		// 验证令牌
		tokenString := parts[1]
		claims, err := parseToken(tokenString, m.Config.Auth.AccessSecret)
		if err != nil {
			logx.Errorf("令牌验证失败: %v", err)
			httpx.WriteJson(w, http.StatusUnauthorized, types.NewErrorResponse(types.ErrInvalidToken, "无效的认证令牌"))
			return
		}

		// 将用户信息添加到请求上下文
		userInfoBytes, err := json.Marshal(claims)
		if err != nil {
			logx.Errorf("序列化用户信息失败: %v", err)
			httpx.WriteJson(w, http.StatusInternalServerError, types.NewErrorResponse(types.ErrInternalServer, "服务器内部错误"))
			return
		}

		r.Header.Set("X-User-Info", string(userInfoBytes))
		next(w, r)
	}
}

// 解析JWT令牌
func parseToken(tokenString, secret string) (map[string]interface{}, error) {
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, errors.New("unexpected signing method")
		}
		return []byte(secret), nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("invalid token")
}

// 获取请求中的用户信息
func GetUserInfo(r *http.Request) (*Claims, error) {
	userInfoStr := r.Header.Get("X-User-Info")
	if userInfoStr == "" {
		return nil, errors.New("no user info found")
	}

	var claims Claims
	err := json.Unmarshal([]byte(userInfoStr), &claims)
	if err != nil {
		return nil, err
	}

	return &claims, nil
}
